package com.yueqian.system.service.impl;

import static com.yueqian.framework.enmus.ExceptionEnum.*;

import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.wf.captcha.ArithmeticCaptcha;
import com.wf.captcha.base.Captcha;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yueqian.framework.enmus.RedisCodeEnum;
import com.yueqian.framework.entity.BaseEntity;
import com.yueqian.framework.entity.LoginUser;
import com.yueqian.framework.entity.VerifyCodeEntity;
import com.yueqian.framework.exception.GlobalException;
import com.yueqian.framework.utils.JwtUtils;
import com.yueqian.framework.utils.RedisUtils;
import com.yueqian.system.converter.RoleConvert;
import com.yueqian.system.converter.UserConvert;
import com.yueqian.system.enmus.StatusEnum;
import com.yueqian.system.entity.Role;
import com.yueqian.system.entity.User;
import com.yueqian.system.entity.UserDept;
import com.yueqian.system.entity.UserRole;
import com.yueqian.system.mapper.UserMapper;
import com.yueqian.system.service.*;
import com.yueqian.system.vo.req.DeptReqVO;
import com.yueqian.system.vo.req.UserReqVO;
import com.yueqian.system.vo.req.UserRoleReqVO;
import com.yueqian.system.vo.res.DeptResVO;
import com.yueqian.system.vo.res.RoleResVO;
import com.yueqian.system.vo.res.UserInfoResVO;
import com.yueqian.system.vo.res.UserResVO;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class SystemUserServiceImpl extends ServiceImpl<UserMapper, User> implements SystemUserService {


	@Resource
	private JwtUtils jwtProvider;


	/**
	 * 密码加密工具类.
	 */
	@Resource
	private PasswordEncoder passwordEncoder;
	/**
	 * JWT工具类.
	 */

	@Resource
	private JwtUtils jwtUtils;


	/**
	 * Spring Security提供的认证管理器.
	 * //
	 */
	@Resource
	private AuthenticationManager authenticationManager;


	@Resource
	private RedisUtils redisUtils;


	@Resource
	private UserRoleService userRoleService;

	@Resource
	private RoleService roleService;

	@Resource
	private UserDeptService userDeptService;

	@Resource
	private DeptService deptService;



	@Override
	public UserResVO getDetail(Long id) {
		//获取所有角色
		List<Role> roleOptions = roleService.selectListData(null);

		//获取部门数据
		DeptReqVO deptReqVO = new DeptReqVO();
		deptReqVO.setId(0L);
		List<DeptResVO> deptOptions = deptService.getDeptChildren(deptReqVO);

		Long deptId = null;

		List<UserDept> userDeptList = this.userDeptService.list(Wrappers.lambdaQuery(UserDept.class)
																		.eq(UserDept::getUserId, id)
																		.orderByDesc(BaseEntity::getCreatorTime));
		if (CollectionUtil.isNotEmpty(userDeptList)) {
			deptId = userDeptList.get(0).getDeptId();
		}
		//新增操作
		if (ObjectUtil.isEmpty(id)) {
			UserResVO userResVO = new UserResVO();
			List<RoleResVO> roleResVOList = RoleConvert.INSTANCE.toResList(roleOptions);
			userResVO.setRoleOptions(roleResVOList);
			userResVO.setDeptOptions(deptOptions);
			userResVO.setDeptId(deptId);
			return userResVO;
		}//编辑
		User user = this.getById(id);
		if (ObjectUtil.isEmpty(user)) {
			throw new RuntimeException("用户不存在");
		}
		UserResVO userResVO = UserConvert.INSTANCE.toRes(user);
		userResVO.setDeptId(deptId);
		List<RoleResVO> roleResVOList = RoleConvert.INSTANCE.toResList(roleOptions);
		userResVO.setRoleOptions(roleResVOList);
		userResVO.setDeptOptions(deptOptions);

		UserRoleReqVO reqVO = new UserRoleReqVO();
		reqVO.setUserId(id);
		//获取用户绑定的角色
		List<UserRole> userRoles = userRoleService.selectListData(reqVO);
		if (CollectionUtil.isNotEmpty(userRoles)) {
			List<Long> roleIds = userRoles.stream().map(UserRole::getRoleId).collect(Collectors.toList());
			userResVO.setRoleIds(roleIds);
		}


		user.setPassword(passwordEncoder.encode(user.getPassword()));

		return userResVO;
	}

	@Override
	public User findByUserName(String username) throws Exception {
		User user = this.getBaseMapper().selectOne(Wrappers.lambdaQuery(User.class)
														   .eq(User::getUsername, username));
		//判断用户是否异常
		this.isExceptionUser(user);
		return user;
	}


	/**
	 * 判断用户是否异常
	 *
	 * @param user 用户信息
	 */
	public void isExceptionUser(User user) {
		if (ObjectUtil.isEmpty(user)) { //用户不存在
			throw new GlobalException(USER_NO_EXIST);
		}
		if (ObjectUtil.equals(StatusEnum.IS_NOT_ENABLE.getCode(), user.getStatus())) { //用户已停用
			throw new GlobalException(USER_NOT_ENABLE);
		}
	}

	@Override
	public Boolean register(String username, String password) throws Exception {
		User user = this.getBaseMapper().selectOne(Wrappers.lambdaQuery(User.class).eq(User::getUsername, username));
		if (ObjectUtil.isNotEmpty(user)) {
			throw new RuntimeException("用户名已经被注册");
		}
		user = new User();
		user.setUsername(username);
		user.setPassword(passwordEncoder.encode(password));
		return save(user);
	}

	@Override
	public String login(UserReqVO reqVO) throws Exception {
		// 获取用户输入的验证码
		String verifyCode = reqVO.getVerifyCode();
		String verifyCodeKey = reqVO.getVerifyCodeKey();
		String verifyCodeRedis = redisUtils.getCacheObject(verifyCodeKey);
		if (ObjectUtil.isEmpty(verifyCodeRedis) || !verifyCode.equals(verifyCodeRedis)) {
			throw new GlobalException(VERIFICATION_CODE_ERROR);
		}
		UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(reqVO.getUsername(), reqVO.getPassword());
		authenticationManager.authenticate(usernamePasswordAuthenticationToken);
		User user = findByUserName(reqVO.getUsername());
		String uuid = UUID.randomUUID().toString().replaceAll("-", "");
		user.setUuid(uuid);
		redisUtils.setCacheObject(uuid, user, 1, TimeUnit.MINUTES);
		LoginUser loginUser = LoginUser.builder().user(user).build();

		//删除验证码
		redisUtils.deleteObject(verifyCodeKey);
		return jwtUtils.generateToken(loginUser);
	}

	public VerifyCodeEntity generateVerifyCode() {
		// 创建验证码对象
		Captcha captcha = new ArithmeticCaptcha();

		// 生成验证码编号
		String verifyCodeKey = RedisCodeEnum.VERIFY_CODE.getKey();

		String verifyCode = captcha.text();

		// 获取验证码图片，构造响应结果
		VerifyCodeEntity verifyCodeEntity = new VerifyCodeEntity(verifyCodeKey, captcha.toBase64(), verifyCode);

		// 存入Redis，设置60s过期
		redisUtils.setCacheObject(verifyCodeKey, verifyCode, 60, TimeUnit.SECONDS);

		return verifyCodeEntity;
	}

	@Override
	public UserInfoResVO getInfo(String token) {
		Collection<? extends GrantedAuthority> roles = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
		List<String> roleList = roles.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
		if (CollectionUtil.isEmpty(roleList)) {
			throw new GlobalException(USER_ROLE_EMPTY);
		}
		final String userName = jwtProvider.extractUserName(token);
		User user = redisUtils.getCacheObject(userName);
		UserInfoResVO userInfoResVO = new UserInfoResVO();
		userInfoResVO.setUsername(user.getUsername());
		userInfoResVO.setIntroduction(user.getIntroduction());
		userInfoResVO.setAvatar(user.getAvatar());
		userInfoResVO.setRoles(roleList);
		return userInfoResVO;
	}

	@Override
	public String logout(String token) {
		final String userName = jwtProvider.extractUserName(token);
		redisUtils.deleteObject(userName);
		SecurityContextHolder.clearContext();
		return "退出成功";
	}

	@Override
	public IPage<UserResVO> selectPageData(UserReqVO reqVO) {
		String startTime = null;
		String endTime = null;
		if (CollectionUtil.isNotEmpty(reqVO.getTime())) {
			startTime = reqVO.getTime().get(0);
			endTime = reqVO.getTime().get(1);
		}
		Page<User> systemUserDTOIPage = (Page<User>) this.baseMapper.selectPage(reqVO.getPage(reqVO.getCurrentPage(), reqVO.getPageSize()), Wrappers.lambdaQuery(User.class)
																																												  .like(StrUtil.isNotBlank(reqVO.getUsername()), User::getUsername, reqVO.getUsername())
																																												  .like(StrUtil.isNotBlank(reqVO.getMobile()), User::getMobile, reqVO.getMobile())
																																												  .eq(ObjectUtil.isNotEmpty(reqVO.getStatus()), User::getStatus, reqVO.getStatus())
																																					.between(CollectionUtil.isNotEmpty(reqVO.getTime()), BaseEntity::getCreatorTime, startTime, endTime)
																																					.orderByDesc(BaseEntity::getCreatorTime));

		return UserConvert.INSTANCE.toPage(systemUserDTOIPage);
	}

	@Override
	public void editStatus(UserReqVO reqVO) {
		User user = UserConvert.INSTANCE.toEntity(reqVO);
		if (ObjectUtil.isEmpty(this.getById(user.getId()))) {
			throw new RuntimeException("用户不存在");
		}
		this.updateById(user);
	}


	@Transactional
	@Override
	public Boolean delete(List<Long> ids) {
		if (CollectionUtil.isEmpty(ids)) {
			return false;
		}
		return this.removeByIds(ids);
	}

	@Override
	public void restPassword(UserReqVO reqVO) {
		String password = reqVO.getPassword();
		reqVO.setPassword(passwordEncoder.encode(password));
		User entity = UserConvert.INSTANCE.toEntity(reqVO);
		this.saveOrUpdate(entity);
	}


	@Transactional
	@Override
	public Long add(UserReqVO reqVO) {
		Long deptId = reqVO.getDeptId();
		//更新插入用户部门关系
		if (ObjectUtil.isNotEmpty(deptId)) {
			UserDept userDept = new UserDept();
			userDept.setUserId(reqVO.getId());
			userDept.setDeptId(reqVO.getDeptId());
			List<Long> ids = this.userDeptService.getBaseMapper().selectList(Wrappers.lambdaQuery(UserDept.class)
																					 .eq(ObjectUtil.isNotEmpty(reqVO.getId()), UserDept::getUserId, reqVO.getId()))
									 .stream().map(BaseEntity::getId).collect(Collectors.toList());
			this.userDeptService.removeByIds(ids);
			this.userDeptService.saveOrUpdate(userDept);

		}

		List<Long> roleIds = reqVO.getRoleIds();
		for (Long roleId : roleIds) {
			Role role = roleService.getById(roleId);
			if (ObjectUtil.isEmpty(role)) {
				throw new RuntimeException("角色不存在");
			}
		}
		//新增用户
		User user = UserConvert.INSTANCE.toEntity(reqVO);
		//新增操作，才有密码
		if (ObjectUtil.isEmpty(reqVO.getId())) {
			//密码加密
			user.setUsername(reqVO.getUsername());
			user.setPassword(passwordEncoder.encode(user.getPassword()));
			this.saveOrUpdate(user);
		} else {
			this.saveOrUpdate(user);
		}
		//用户分配角色
		userRoleService.add(user.getId(), roleIds);
		return user.getId();
	}

}
